/*
 * Copyright (c) 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.libermundi.theorcs.chronicles.tapestry.services;

import org.apache.tapestry5.ioc.Configuration;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.InjectService;
import org.apache.tapestry5.ioc.annotations.SubModule;
import org.apache.tapestry5.ioc.annotations.Value;
import org.apache.tapestry5.ioc.services.Coercion;
import org.apache.tapestry5.ioc.services.CoercionTuple;
import org.apache.tapestry5.services.ApplicationInitializerFilter;
import org.apache.tapestry5.services.LibraryMapping;
import org.apache.tapestry5.services.ValueEncoderFactory;
import org.libermundi.theorcs.chronicles.ChronicleConstants;
import org.libermundi.theorcs.chronicles.model.Chronicle;
import org.libermundi.theorcs.chronicles.model.Faction;
import org.libermundi.theorcs.chronicles.model.Persona;
import org.libermundi.theorcs.chronicles.services.ChronicleManager;
import org.libermundi.theorcs.chronicles.services.FactionManager;
import org.libermundi.theorcs.chronicles.services.PersonaManager;
import org.libermundi.theorcs.chronicles.tapestry.encoders.PersonaEncoder;
import org.libermundi.theorcs.chronicles.tapestry.services.impl.ChronicleNavItemSource;
import org.libermundi.theorcs.chronicles.tapestry.services.impl.FactionMenuStringSource;
import org.libermundi.theorcs.chronicles.tapestry.services.impl.FactionNavItemSource;
import org.libermundi.theorcs.core.services.StringSource;
import org.libermundi.theorcs.core.util.OrcsHome;
import org.libermundi.theorcs.layout.services.NavItemSource;


@SubModule(ChronicleMenuModule.class)
public class ChronicleModule {
	public static void contributeComponentClassResolver(final Configuration< LibraryMapping > configuration) {
        configuration.add(new LibraryMapping(ChronicleConstants.TAPESTRY_MAPPING, "org.libermundi.theorcs.chronicles.tapestry"));
	}
	
	public static void bind(ServiceBinder binder) {
//		//bind the different MessageService into MessageChainService 
//        binder.bind(MessageChainService.class, ActivityServiceImpl.class).withId("ActivityService");
//        binder.bind(MessageChainService.class, ExternalEmailServiceImpl.class).withId("ExternalEmailService");
//        binder.bind(MessageChainService.class, ForumServiceImpl.class).withId("ForumService");
//        binder.bind(MessageChainService.class, InstantMessengingServiceImpl.class).withId("InstantMessengingService");
//        binder.bind(MessageChainService.class, InternalEmailServiceImpl.class).withId("InternalEmailService");
        
        binder.bind(NavItemSource.class, ChronicleNavItemSource.class).withId("ChronicleNavItemSource");
        binder.bind(NavItemSource.class, FactionNavItemSource.class).withId("FactionNavItemSource");
        binder.bind(StringSource.class, FactionMenuStringSource.class).withId("FactionMenuStringSource");
    }
	
//	/**
//	 * Order the construction of MessageChainService
//	 * @param commands ordered configuration of messageChainService
//	 * @param activityService 
//	 * @param externalEmailService
//	 * @param forumService
//	 * @param instantMessengingService
//	 * @param internalEmailService
//	 */
//	@SuppressWarnings("rawtypes")
//	public static void contributeMessageChainService(OrderedConfiguration<MessageChainService> commands,
//			@InjectService("ActivityService") MessageChainService activityService,
//			@InjectService("ExternalEmailService") MessageChainService externalEmailService,
//			@InjectService("ForumService") MessageChainService forumService,
//			@InjectService("InstantMessengingService") MessageChainService instantMessengingService,
//			@InjectService("InternalEmailService") MessageChainService internalEmailService
//			) {
//		
//		commands.add("InstantMessengingService", instantMessengingService);
//		commands.add("InternalEmailService", internalEmailService, "after:InstantMessengingService");
//		commands.add("ForumService", forumService, "after:InternalEmailService");
//		commands.add("ExternalEmailService", externalEmailService, "after:ForumService");
//		commands.add("ActivityService", activityService, "after:ExternalEmailService");
//			
//		
//	}
//	
//	/**
//	 * Build MessageChainService
//	 * @param commands
//	 * @param chainBuilder
//	 * @return
//	 */
//	@SuppressWarnings("rawtypes")
//	public static MessageChainService buildMessageChainService(List<MessageChainService> commands, 
//			    @InjectService("ChainBuilder")
//			    ChainBuilder chainBuilder) {
//		return chainBuilder.build(MessageChainService.class, commands);
//	}
	
	public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration) {
        configuration.add("chronicles.assets", "org/libermundi/theorcs/chronicles/tapestry/assets");

        configuration.add("chronicles.scripts", "classpath:${chronicles.assets}/js");
        configuration.add("chronicles.styles", "classpath:${chronicles.assets}/css");
        configuration.add("chronicles.images", "classpath:${chronicles.assets}/images");
    }	
	
	public static void contributeComponentMessagesSource(
			@Value("META-INF/lang/chronicles.properties")
			Resource chroniclesCatalogResource,
			OrderedConfiguration<Resource> configuration) {
			configuration.add("ChroniclesCatalog", chroniclesCatalogResource, "before:AppCatalog");
	}
	
	public static void contributeApplicationConfiguration(
			OrderedConfiguration<String> configuration,
			OrcsHome theOrcsHome) {
		configuration.add("chronicles-default", "classpath://META-INF/conf/chronicles-default.properties","after:core-default");
		configuration.add("chronicles-local", theOrcsHome.getPath() + "/conf/chronicles.properties","after:chronicles-default");
	}
	
	public void contributeApplicationInitializer(OrderedConfiguration<ApplicationInitializerFilter> configuration) {
        configuration.add("chroniclesModuleInitializer", new ChroniclesModuleInitializer(), "after:securityModuleInitializer");
    }
	
	@SuppressWarnings("rawtypes")
	public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration,
			@InjectService("chronicleManager") final ChronicleManager chronicleManager,
			@InjectService("personaManager") final PersonaManager persoManager,
			@InjectService("factionManager") final FactionManager factionManager) {
		
		Coercion<Long, Chronicle> c1 = new Coercion<Long, Chronicle>() {
			@Override
			public Chronicle coerce(Long input) {
				return chronicleManager.load(input);
			}
		};
		
		Coercion<Long, Persona> c2 = new Coercion<Long, Persona>() {
			@Override
			public Persona coerce(Long input) {
				return persoManager.load(input);
			}
		};
		
		Coercion<Long, Faction> c3 = new Coercion<Long, Faction>() {
			@Override
			public Faction coerce(Long input) {
				return factionManager.load(input);
			}
		};		
		
		configuration.add(new CoercionTuple<>(Long.class, Chronicle.class, c1));
		configuration.add(new CoercionTuple<>(Long.class, Persona.class, c2));
		configuration.add(new CoercionTuple<>(Long.class, Faction.class, c3));
		
	}
	
	/**
	 * Contribute for the Encoder 
	 * @param configuration
	 */
	@SuppressWarnings("rawtypes")
	public static void contributeValueEncoderSource(MappedConfiguration<Class,ValueEncoderFactory> configuration) { 
		 configuration.addInstance(Persona.class, PersonaEncoder.class);
	 }

}
